﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Windows.Storage;
using Daphne.GameShared;
using System.Threading.Tasks;

namespace Daphne.MiddleLayerModule
{
    /// <summary>
    /// Licence file parser - not very robust I must admit
    /// TO-DO: make exception raising when errors occur
    /// TO-DO: complete commenting
    /// </summary>
    internal class LicensesParser: ILicensesParser
    {

        private string _sLicenceFileName = "licenses.ini";

        // TO-DO: find better way to set the license path
        private string _sLicenceDir = "ms-appx:///AppData/Licenses";

        // file content container
        private IList<string>  _fileContent;
        private string _licenseFileContent;
        private int _lContentIndex;

        // license tokens
        private string _sProgramHeader = "Header";
        private string _sLibraryHeader = "Libraries";
        private string _sProgramNameToken = "ProgramName";
        private string _sURLToken = "CodeUrl";
        private string _sLibraryToken = "Library";

        public LicensesParser()
        {
            LibraryRecords = new List<LibraryRecord>();
            _licenseFileContent = string.Empty;
        }

        // output resuls
        public string ProgramName
        { get; set; }

        public string ProgramURL
        { get; set; }

        public List<LibraryRecord> LibraryRecords
        { get; set; }

        public string LicenseFileContent
        {
            get { return _licenseFileContent; }
        }


        /// <summary>
        /// The main parsing method
        /// </summary>
        /// <returns></returns>
        async public Task Parse()
        {
            LibraryRecords.Clear();

            // load the file content
            string sPath = _sLicenceDir + "/" + _sLicenceFileName;
            
            // open file asynch
            StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(sPath));
            if (file == null)
                return;

            // read the content of the file
            _fileContent = await FileIO.ReadLinesAsync(file);
                      
            _lContentIndex = 0;
            // parse header
            if (ParseHeader() == false)
                return;

            // parse libraries
            if (ParseLibraries() == false)
                return;
        }

        /// <summary>
        /// Loads the license file
        /// </summary>
        public async Task LoadLicenseFileAsync(string fileName)
        {
            // formats the App Uri
            string appUri = _sLicenceDir + "/"  + fileName;

            // returns the file
            StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(appUri));
            if (file == null)
                return;

            // read the content
            _licenseFileContent = await FileIO.ReadTextAsync(file);
        }


        /// <summary>
        /// Parse libraries
        /// </summary>
        private bool ParseLibraries()
        {
            // find the header
            if (FindHeader(_sLibraryHeader) == false)
                return false;

            // interate to the end of file
            while (_lContentIndex < _fileContent.Count)
            {
                string s = _fileContent[_lContentIndex];

                // check empty string
                if (string.IsNullOrWhiteSpace(s) == true)
                    break;

                // is it library record?
                if (s.Contains(_sLibraryToken) == true)
                {
                    int index = s.IndexOf('=');
                    if (index >= 0)
                    {
                        s = s.Substring(index + 1);
                        string[] parts = s.Split(';');

                        // create new record
                        if (parts.Length >= 3)
                        {
                            LibraryRecord libRec = new LibraryRecord();
                            libRec.LibraryName = RemoveQuotes(parts[0]);
                            libRec.Author = RemoveQuotes(parts[1]);
                            libRec.URL = RemoveQuotes(parts[2]);
                            libRec.LicenseFile = RemoveQuotes(parts[3]);

                            LibraryRecords.Add(libRec);
                        }
                    }
                }

                _lContentIndex++;
            }

            return true;
        }

        /// <summary>
        /// Header parsing method
        /// </summary>
        /// <returns></returns>
        private bool ParseHeader()
        {
            if(FindHeader(_sProgramHeader) == false)
                return false;

            // extract values
            ProgramName = RemoveQuotes(GetTokenValue(_sProgramNameToken, _fileContent[_lContentIndex]));
            _lContentIndex++;
            ProgramURL = RemoveQuotes(GetTokenValue(_sURLToken, _fileContent[_lContentIndex]));

            return true;
        }

        /// <summary>
        /// Find the specific header in the license file
        /// Index is increment for the next line
        /// </summary>
        private bool FindHeader(string sHeader)
        {
            sHeader = '[' + sHeader + ']';
            while (_lContentIndex < _fileContent.Count)
            {
                if (_fileContent[_lContentIndex].Contains(sHeader))
                {
                    _lContentIndex++;
                    return true;
                }

                _lContentIndex++;
            }

            return false;
        }

        /// <summary>
        /// Extracts the token value
        /// </summary>
        private string GetTokenValue(string sToken, string sLine)
        {
            if (sLine.Contains(sToken) == false)
                return string.Empty;
            int index = sLine.IndexOf('=');
            if (index < 0)
                return string.Empty;

            string sValue = sLine.Substring(index + 1);
            return sValue;         
        }

        /// <summary>
        /// Removes the quotes from the string value
        /// </summary>
        private string RemoveQuotes(string sValue)
        {
            int index = sValue.IndexOf('"');
            if (index >= 0)
                sValue = sValue.Substring(index + 1);
            index = sValue.IndexOf('"');
            if(index >= 0)
                sValue = sValue.Substring(0, index);
            return sValue;                                   
        }
    }
}
